import socket, threading, queue, json, time
from config import config
from widgetCom import queueDeletegateTx, queueDeletegateRx
from msg import Msg
import select
from log import logger


class ForwardServer(threading.Thread):
    def __init__(self) -> None:
        super().__init__()
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setblocking(False)
        self.mapTable = []
        self.daemon = True
        self.inputs = [self.server]
        self.outputs = []
        
        
    def mapTableRefresh(self, client, deviceId):
        for item in self.mapTable:
            if item["client"] == client:
                item["deviceId"] = deviceId
                break
        else:
            self.mapTable.append({"client": client, "deviceId":deviceId})

    
    def mapTableRemove(self, client):
        for item in self.mapTable:
            if item["client"] == client:
                try:
                    self.mapTable.remove(item)
                except Exception:
                    pass


    def clientRemove(self, client):
        if client in self.outputs:
            self.outputs.remove(client)
        self.inputs.remove(client)
        client.close()
        self.mapTableRemove(client)

    def run(self):
        try:
            self.server.bind(("", config["forwardServer"]["port"]))
            self.server.listen()
        except Exception as e:
            logger.info("[FowardServer] Open forward server failed, info is %item" % e.__str__())     
            return         

        while True:
            
            readable, writable, exceptional = select.select(self.inputs, self.outputs, self.inputs, 0.1)
            # 可读
            for item in readable:
                if item is self.server:             # 是服务器, 则允许链接, 并把客户端加入读取列表中
                    connectId, clientAddr = item.accept()
                    logger.info("[ForwardServer] Get connect " + clientAddr.__str__())
                    self.inputs.append(connectId)
                elif item is queueDeletegateRx:     # 是委托接收, 则取出并且发送出去
                    response = queueDeletegateRx.get()
                    responseInfo = json.loads(response.decode("utf8"))
                    
                    for i in range(len(self.mapTable)):
                        if self.mapTable[i]["deviceId"] == responseInfo.get("deviceId"):
                            logger.info(responseInfo)
                            # self.server.sendto(response, (self.mapTable[i]["ip"], self.mapTable[i]["port"]))
                else:                               # 是客户端, 接收数据并处理
                    try:
                        data = item.recv(4096)   
                    except Exception:
                        self.clientRemove(item)
                        continue
                    logger.info("----------------------------------------------")
                    logger.info("[ForwardServer] Recv , content length = %d" % (len(data)))
                    if len(data) == 0:
                        self.clientRemove(item)

                    result, errInfo = Msg.jsonFormatCheck(data)
                    if result == False:
                        logger.info("[ForwardServer] %s" % errInfo)
                        logger.info(data)
                    else:
                        msgInfo = json.loads(data.decode("utf8"))
                        logger.info(msgInfo)
                        queueDeletegateTx.put(data)
                        self.mapTableRefresh(item, msgInfo["deviceId"])     # 刷新映射表
                        

                # 异常
                for item in exceptional:
                    self.clientRemove(item)
                    logger.info("remove ---------------------------")


            # 处理回复报文
            try:
                response = queueDeletegateRx.get_nowait()
            except queue.Empty as e:
                response = None

            if response != None:
                responseInfo = json.loads(response.decode("utf8"))

                for item in self.mapTable:
                    if item["deviceId"] == responseInfo.get("deviceId"):
                        try:
                            item["client"].send(response)
                        except:
                            pass